package com.apkdv.mvvmfast.ext

import com.apkdv.mvvmfast.network.config.HttpCode
import com.apkdv.mvvmfast.network.exception.ApiException
import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart


/**
 * 用流的方式进行网络请求
 */
fun <T> launchWithFlow(
    block: suspend () -> T,
    error: (ApiException) -> Unit = {},
    complete: () -> Unit = {},
    isShowDialog: Boolean = false,
    handleError: Boolean = true,
    defUi: UIChange? = null,
): Flow<T> {
    return flow {
        emit(block())
    }.onStart {
        if (isShowDialog) defUi?.showDialog?.call()
    }.onCompletion { cause ->
        cause?.let { e ->
            val case = if (e is ApiException)
                e
            else {
                ApiException.handleException(e)
            }
            if (HttpCode.FRAME_WORK.REQUEST_CANCEL.toLong() != case.code)
                error(case)
            if (handleError)
                handleError(case, defUi)
        }
        if (isShowDialog) defUi?.dismissDialog?.call()
        complete()
    }
}

/**
 * 异常统一处理
 */
private suspend fun <T> handleException(
    block: suspend CoroutineScope.() -> T,
    success: suspend CoroutineScope.(T) -> Unit,
    error: suspend CoroutineScope.(ApiException) -> Unit,
    complete: suspend CoroutineScope.() -> Unit,
    handleError: Boolean = false,
) {
    coroutineScope {
        try {
            success(block())
        } catch (e: Throwable) {
            topHandleError(e, error, handleError)
        } finally {
            complete()
        }
    }
}


private suspend fun topHandleError(
    e: Throwable, error: suspend CoroutineScope.(ApiException) -> Unit,
    handleError: Boolean, defUi: UIChange? = null,
) {
    coroutineScope {
        val exp = if (e is ApiException) {
            e
        } else {
            ApiException.handleException(e)
        }
        if (HttpCode.FRAME_WORK.REQUEST_CANCEL.toLong() != exp.code)
            error(exp)
        if (handleError)
            handleError(exp, defUi)
    }
}

/***
 * 处理onError中错误
 * @param ex ApiException
 */
fun handleError(ex: ApiException?, defUi: UIChange?) {
    if (ex == null) {
        return
    }
    when (ex.code) {
        HttpCode.HTTP.INNER_EXCEPTION.toLong(),
        HttpCode.HTTP.SERVICE_UNUSEFUL.toLong(),
        -> {
            "出了点问题".showToast()
            defUi?.showError?.call()
        }
        HttpCode.FRAME_WORK.NETWORK_ERROR.toLong(),
        HttpCode.FRAME_WORK.TIMEOUT_ERROR.toLong(),
        -> defUi?.showNoNet?.call()
        HttpCode.HTTP.UNAUTHORIZED.toLong() -> {
            "登录信息异常，请重新登录".showToast()
        }
        HttpCode.FRAME_WORK.REQUEST_CANCEL.toLong() -> {
            LogUtils.e("请求取消")
        }
        else -> {
            LogUtils.e(ex.message.toString())
            defUi?.showError?.call()
        }

    }
}


/**
 * 异常统一处理
 */
private suspend fun handleException(
    block: suspend CoroutineScope.() -> Unit,
    error: suspend CoroutineScope.(ApiException) -> Unit,
    complete: suspend CoroutineScope.() -> Unit,
    handleError: Boolean,
) {
    coroutineScope {
        try {
            block()
        } catch (e: Throwable) {
            topHandleError(e, error, handleError)
        } finally {
            complete()
        }
    }
}